﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;
using System.Windows;
using System.Windows.Controls;
using DataProcessing;
using System.Threading.Tasks;

namespace Gene.Render
{
    public class Scene
    {
        static Scene _instance = null;
        public static Scene Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new Scene();
                return _instance;
            }
        }
        public static Scene NewInstance
        {
            get
            { _instance = new Scene();
            return _instance;
            }
        }
        public const int X_ZERO_POINT = -1;
        const double Pi = 3.141592653589793f;
  
 
        Transform3D iniTransform;
   

        public int drawProgress = 0;
        
        Model3DGroup _ModelGroup = new Model3DGroup();

        ModelVisual3D _modelHolder = new ModelVisual3D();

        //PerspectiveCamera _Camera = new PerspectiveCamera();
        OrthographicCamera _Camera = new OrthographicCamera();
        
        Viewport3D _Viewport3D = new Viewport3D();
        Plane3D[] _planes =null;
        XYPlane _xyPlane = new XYPlane();
        XZPlane _xzPlane = new XZPlane();
        Vector3D _LookDirection = new Vector3D(0, 0, -1);
        Point3D _standAt = new Point3D(0, 0, 3.6);//looking at -1,-1,0
        Vector3D _up ;//= Vector3D.CrossProduct(_LookDirection,);// new Vector3D(0, 0, 1);
        const int SCENE_X_ROTATE = -10;
        const int SCENE_Y_ROTATE = 100;
        private Scene()
        {
            _planes= new Plane3D[Settings.Instance.ChromeCount];
            BuildCamera();
            BuildLights();
            BuildPlanes();
            BulidXYCoordinate();
            BulidXZCoordinate();
            // Add the group of models to the ModelVisual3d.
            _modelHolder.Content = _ModelGroup;

            _Viewport3D.Children.Add(_modelHolder);
            Rotate(SCENE_X_ROTATE, SCENE_Y_ROTATE);
            iniTransform = _modelHolder.Transform;
            ChromePairData.Align = ChromePairData.AlignMode.LeftJustify;
        }
        private void BulidXYCoordinate()
        {
            _ModelGroup.Children.Remove(_xyPlane.GeometryModel);
            _xyPlane.Build();
            _ModelGroup.Children.Add(_xyPlane.GeometryModel);
        }
        private void BulidXZCoordinate()
        {
            _ModelGroup.Children.Remove(_xzPlane.GeometryModel);
            _xzPlane.Build();
            _ModelGroup.Children.Add(_xzPlane.GeometryModel);
        }
        public const double PLANE_Z_INTERVAL = 0.1;
        private void BuildPlanes()
        {
            ZCoordinatePlanes = new List<TextPlane>();
            // The geometry specifes the shape of the 3D plane. 
            for (int i = 0; i < _planes.Length; i++)
            {
                _planes[i] = new Plane3D();
                _planes[i].Z = ZOfPlane(i);

                ZCoordinatePlanes.AddRange(BuildZCoordinatePlane(_planes[i].Z,
                                                            Settings.Instance.ChromeSettingList[i].DisplayName));

                ChromeDataImg img = new ChromeDataImg();
                _planes[i].Image = img;
                _planes[i].AddTo(_ModelGroup);
                SetPlaneContent(i, img.RenderImage);

            }

            foreach (TextPlane plane in ZCoordinatePlanes)
            {
                plane.AddTo(_ModelGroup);
            }

        }

        /// <summary>
        /// 上下各一个，不能被xz平面挡住
        /// </summary>
        /// <param name="z"></param>
        /// <returns></returns>
        List<TextPlane> BuildZCoordinatePlane(double z,String text)
        {
            Size planeSize = new Size(0.11,0.11);
            List<TextPlane> ret = new List<TextPlane>();

            Point leftUp = new Point();
            leftUp.X = X_ZERO_POINT-planeSize.Width;
            leftUp.Y = z - planeSize.Height / 2;
            ret.Add(new TextPlane(leftUp, planeSize.Width, planeSize.Height, XZPlane.Y + 0.01,text));
            
            return ret;

               
               
        }
        /// <summary>
        /// 便于管理
        /// </summary>
        private List<TextPlane> ZCoordinatePlanes
        {
            get;
            set;
        }
        static public double ZOfPlane(int i)
        {
            return XYPlane.Z - PLANE_Z_INTERVAL * i;
        }

        static public int PlaneOfZ(double z)
        {
            int index= (int)((XYPlane.Z - z) / PLANE_Z_INTERVAL);
            return Util.Truncate(0, Settings.Instance.ChromeCount - 1, index);
           
        }

        private void BuildCamera()
        {
            _up = new Vector3D(0, 1, 0); //Vector3D.CrossProduct(_LookDirection, new Vector3D(0, -1, 0));
            _Camera.Position = _standAt;

            // Specify the direction that the camera is pointing.
            _Camera.LookDirection = _LookDirection;

            _Camera.UpDirection = _up;
            _Camera.Width = 2.4;
            
            // Asign the camera to the viewport
            _Viewport3D.Camera = _Camera;
        }

        private void BuildLights()
        {

            DirectionalLight light2 = new DirectionalLight();
            light2.Color = Colors.White;
            light2.Direction = new Vector3D(0, -1, -1);
           
            _ModelGroup.Children.Add(light2);
        }
    

        public void AddTo(UIElementCollection uiCollection)
        {
            
            uiCollection.Add(_Viewport3D);
        }
        public void Invalidate()
        {
            _Viewport3D.InvalidateVisual();
            
            
            
        }
        public void Transform(Transform3D trans)
        {
            Transform3DGroup transGroup = new Transform3DGroup();
            transGroup.Children.Add(_modelHolder.Transform);
            transGroup.Children.Add(trans);
            _modelHolder.Transform = transGroup;

      
            _Viewport3D.InvalidateVisual();
        }
        public Transform3D GetTransform()
        {
            return _modelHolder.Transform;
        }
        public void TurnLeftRight(double angle)
        {
            
            AxisAngleRotation3D rotate = new AxisAngleRotation3D(_up, angle);
            Transform3D trans = new RotateTransform3D(rotate);
            Transform(trans);
        }

        public void RotateZ(double dz)
        {
            double rotZ = (Pi * dz * 16 / 180.0f);

            AxisAngleRotation3D rotateZ = new AxisAngleRotation3D(new Vector3D(0, 0, 1), rotZ);
            Transform3DGroup transformGroup = new Transform3DGroup();
            transformGroup.Children.Clear();
            transformGroup.Children.Add(new RotateTransform3D(rotateZ));
            Transform(transformGroup);
        }
        public void Rotate(double dx, double dy)
        {
            double rotX = (Pi * dy * 16 / 180.0f);
            double rotY = (Pi * dx * 16 / 180.0f);
            
            

            AxisAngleRotation3D rotateX = new AxisAngleRotation3D(new Vector3D(1, 0, 0), rotX);

            AxisAngleRotation3D rotateY = new AxisAngleRotation3D(new Vector3D(0, 1, 0), rotY);

            Transform3DGroup transformGroup = new Transform3DGroup();
            transformGroup.Children.Clear();
            transformGroup.Children.Add(new RotateTransform3D(rotateX));
            transformGroup.Children.Add(new RotateTransform3D(rotateY));
            Transform(transformGroup);
            
        
        }

        public void TranformFromOrigin(Transform3D tranform)
        {
            _modelHolder.Transform = tranform;
        }
        public void ResetTransform()
        {
            _modelHolder.Transform = iniTransform;
        }


     
        public void Zoom(double delta, Point3D centerPoint)
        {
            
            //if (zoomDelta <= 1.5 && zoomDelta >= 0.5)
            //{
            ScaleTransform3D scale = new ScaleTransform3D();

            scale.CenterX = centerPoint.X;
            scale.CenterY = centerPoint.Y;
            scale.CenterZ = centerPoint.Z;
            scale.ScaleX = delta;
            scale.ScaleY = delta ;
            scale.ScaleZ = delta ;

            
            Transform(scale);
         }
        public void Move(Vector3D offset)
        {
            TranslateTransform3D trans = new TranslateTransform3D(offset);
            Transform(trans);
        }

        public void drawXYCoordinate(ValueRange range)
        {
            _ModelGroup.Children.Remove(_xyPlane.GeometryModel);
            //_xyPlane.Build();
            _xzPlane.drawXCoordinateText(range);

            
            _ModelGroup.Children.Add(_xyPlane.GeometryModel);
        }
        public void SetPlaneContent(int chIndex,RenderTargetBitmap img)
        {
            
            Plane3D plane = _planes[chIndex];
            plane.Drawer = new ImageBrush(img);
            
            _ModelGroup.Children.Remove(plane.GeometryModel);
            plane.Build();

            _ModelGroup.Children.Add(plane.GeometryModel);
  
        }
        public void DrawAllPlanes(ChromePairData[] data)
        {
            if (data == null)
                return;

            int t1 = Environment.TickCount;
            Parallel.For(0, data.Length, i =>
            {
                _planes[i].DrawData(data[i]);
            });
            int t2 = Environment.TickCount;
            int elapse1 = t2 - t1;
            Color[] colors = new Color[4];
            colors[0] = Colors.SkyBlue;
            colors[1] = Colors.Yellow;
            colors[2] = Colors.White;
            colors[3] = Colors.HotPink;
            for (int j = 0; j < data.Length; j++)
            {
                //y画在最近，1最远
                //uint zCoordinate = ChrIndex2ZCoodinate(data[i].Number);
                _planes[j].ToScreenModel(colors[j%4]);

            };
            int t3 = Environment.TickCount;
            int elapse2 = t3 - t2;
            drawProgress+=data.Length;
            //for (i = 0; i < data.Length; i++)
            //{

            //   // SetPlaneContent(i, _planes[i].Image.RenderImage);
            //}
                
            
        }

    }
}
